<script lang="ts">
import {
  computed,
  defineComponent,
  onMounted,
  onUnmounted,
  PropType,
  reactive,
  ref,
} from 'vue'
import { Watcher } from 'resize-watcher'

export default defineComponent({
  name: 'ImageCover',
  props: {
    src: {
      type: String,
      default: '',
    },
    information: {
      type: Array as PropType<ImageCoverType[]>,
      default: () => [],
    },
    floatInfo: {
      type: Array as PropType<ImageCoverType2[]>,
      default: () => [],
    },
  },
  setup(props) {
    const ImageRef = ref<HTMLElement>()
    const MainRef = ref<HTMLElement>()

    let watcher: Watcher | undefined

    const svgStyle = reactive({
      width: 0,
      height: 0,
      imgOriginWidth: 0,
      imgOriginHeight: 0,
      imgWidth: 0,
      imgHeight: 0,
    })

    const imageZoom = computed(() => {
      const zoom = svgStyle.imgWidth / svgStyle.imgOriginWidth
      if (Number.isNaN(zoom) || !Number.isFinite(zoom) || !zoom) return 0
      return zoom
    })

    const polylineCalculation = computed(() => {
      return (path: number[][]) => {
        return path
          .map(item => {
            return `${item[0]},${item[1]}`
          })
          .join(' ')
      }
    })

    function imageSizeChangeHandler(res?: DOMRectReadOnly) {
      if (res) {
        svgStyle.imgWidth = res.width
        svgStyle.imgHeight = res.height
      }
      if (ImageRef.value) {
        svgStyle.width = ImageRef.value?.scrollWidth
        svgStyle.height = ImageRef.value?.scrollHeight
      }
    }

    onMounted(() => {
      const imageLoader = new Image()
      imageLoader.src = props.src
      imageLoader.onload = () => {
        svgStyle.imgOriginWidth = imageLoader.width
        svgStyle.imgOriginHeight = imageLoader.height
      }

      if (ImageRef.value) {
        watcher = Watcher.create(ImageRef.value, {
          immediate: true,
          handler: imageSizeChangeHandler,
        })
        watcher.mount()
      }
    })

    onUnmounted(() => {
      if (watcher) watcher.unmount()
    })

    return {
      MainRef,
      ImageRef,
      svgStyle,
      polylineCalculation,
      imageZoom,
    }
  },
})
</script>

<template>
  <div class="image-cover" ref="MainRef">
    <div
      class="floating-box"
      :class="{ hide: !imageZoom }"
      v-if="floatInfo.length && imageZoom"
      :style="{
        transform: `scale(${imageZoom})`,
      }"
    >
      <p
        class="floating-box__item"
        v-for="(item, index) in floatInfo"
        :key="index"
      >
        <span>{{ item.span }}</span
        >：<span
          >{{ item.value }}{{ item.suffix ? ` ${item.suffix}` : '' }}</span
        >
      </p>
    </div>
    <div class="image-container">
      <div class="information-box" :class="{ hide: !imageZoom }">
        <svg
          v-if="imageZoom"
          :width="svgStyle.width / imageZoom"
          :height="svgStyle.height / imageZoom"
          :style="{
            transform: `scale(${imageZoom})`,
            transformOrigin: '0 0',
          }"
        >
          <g v-for="(group, groupIndex) in information" :key="groupIndex">
            <text
              :x="group.position[0]"
              :y="group.position[1]"
              :font-size="20"
              fill="#7DBFFF"
            >
              {{ group.span }}：{{ group.value
              }}{{ group.suffix ? ` ${group.suffix}` : '' }}
            </text>
            <polyline
              :points="polylineCalculation(group.path)"
              fill="none"
              stroke="#7DBFFF"
              stroke-width="1"
            ></polyline>
          </g>
        </svg>
      </div>
      <div class="image-box" ref="ImageRef">
        <img class="main-image" :src="src" alt="" />
      </div>
    </div>
  </div>
</template>

<style scoped lang="scss">
.image-cover {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  overflow: hidden;
  justify-content: center;

  .image-container {
    position: relative;
  }

  .floating-box {
    position: absolute;
    right: 10px;
    top: 10px;
    border: 1px solid #fff;
    padding: 10px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    transform-origin: 100% 0;
    transition: all 0.25s ease-in-out;

    &.hide {
      opacity: 0;
    }

    p {
      line-height: 1.2;
      font-size: 20px;
    }
  }

  .image-box {
    padding: 8%;
    box-sizing: border-box;
  }

  .information-box {
    position: absolute;
    z-index: 2;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;

    &.hide {
      opacity: 0;
    }

    svg {
      transition: all 0.3s ease-in-out;
    }
  }

  .main-image {
    position: relative;
    z-index: 1;
    display: block;
    width: 100%;
  }
}
</style>
